// Lex.cpp: implementation of the Lex class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "8085.h"
#include "InstructionSet.h"
#include "Lex.h"
#include "constants.h"
#include "MyException.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

#define ISCOMMENT(x)    ((x==';') || (x=='#') || (x=='\0'))
#define ISSEPERATOR(x)  (isspace(x) || (x==','))

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

Lex::Lex() : BaseLex()
{
    Init();
}

Lex::Lex(char *str) : BaseLex(str)
{
    Init();
}

Lex::~Lex()
{

}

//////////////////////////////////////////////////////////////////////
// Implementation
//////////////////////////////////////////////////////////////////////

void Lex::Init()
{
    m_nLineNum = 1;
}

int Lex::Advance()
{
    return m_nToken = BaseLex::Advance();
}

///////////////////////////////////////////////////////////
//
int Lex::NextToken()
{
    int ret;
	int i=0;

    if((ret=BaseLex::NextToken())==EOLN) 
    {
        m_nLineNum++;
        return ret; // got an empty string
    }
    if(ISCOMMENT(*m_pStr))
    {
        strcpy(m_szToken,m_pStr);
        m_pStr = m_pStr+strlen(m_pStr);
        return COMMENT;  // got a comment hence skip till end of line
    }
    if(*m_pStr=='.')  // is it a directive
    {
        m_pStr++;
        for(i=0; isalpha(*m_pStr) ; m_pStr++, i++)
            m_szToken[i] = *m_pStr;
        m_szToken[i] = '\0';
        return DIRECTIVE;
    }
    if(isalpha(*m_pStr) || (*m_pStr=='_'))
    {
        for(i=0 ;isalnum(*m_pStr) ; m_pStr++,i++)
            m_szToken[i] = *m_pStr;
        m_szToken[i] = '\0';
        if(*m_pStr==':')
        {
            ++m_pStr;
            return LABEL;
        }
        if(ret=IsInstruction(m_szToken)) return INSTRUCTION;
        return IDENTIFIER; // got a identifier
    }

    if((ret=IsNumeric()))  // check to see if token is a numeric constant
        return ret;
    m_szToken[1] = 0;
    switch(*m_pStr)
    {
        case ';'        : m_szToken[0] = ';'; ++m_pStr; return SEMI;
        case ':'        : m_szToken[0] = ':'; ++m_pStr; return COLON;
        case ','        : m_szToken[0] = ','; ++m_pStr; return COMMA;
        default         : 
            {
                ThrowException(severe,syntax_error,"NextToken : Syntax Error");
                return SYNTAX_ERROR;
            }
    }
}

///////////////////////////////////////////////////////////
//
int Lex::IsNumeric()
{
	int i = 0;
    if(*m_pStr=='0')  
    {
        m_pStr++; // skip the zero
        if(*(m_pStr)=='x')
        {
            m_pStr++; //skip the token 'x'
            for(i=0; isxdigit(*m_pStr) ; m_pStr++,i++)
                m_szToken[i] = *m_pStr;
            m_szToken[i] = '\0';
            if(ISSEPERATOR(*m_pStr) || ISCOMMENT(*m_pStr))
                return HEX;  // got a hexadecimal number
            ThrowException(severe,illegal_hex_number,"Illegal Hexadecimal number");
        }
        for(i=0 ; ((*m_pStr)>='0') && ((*m_pStr)<='7') ; m_pStr++,i++)
                m_szToken[i] = *m_pStr;
            m_szToken[i] = '\0';
        if(ISSEPERATOR(*m_pStr) || ISCOMMENT(*m_pStr))
            return OCTAL;
         ThrowException(severe,illegal_octal_number,"Illegal Octal number");
    }
    if(isdigit(*m_pStr))
    {
        for(i=0; isdigit(*m_pStr) ; m_pStr++,i++)
                m_szToken[i] = *m_pStr;

        m_szToken[i] = '\0';
        if((*m_pStr)=='b')
        {
            for(i=0; m_szToken[i] ; i++)
                if(m_szToken[i]!='0' || m_szToken[i]!='1')
                    ThrowException(severe,illegal_bin_number,"Illegal binary number");
            m_pStr++;
            return BINARY;  // got a binary number
        }
        return DECIMAL;  // got a decimal number
    }
    return 0;
}

///////////////////////////////////////////////////////////
//

CString
Lex::GetErrorPrefix()
{
    m_szErrorPrefix.Format("Line - %d, Column %d",GetLineNumber(),GetColumn());
    if(::nDebugPrefix)
        m_szErrorPrefix = "Lex " +  m_szErrorPrefix;
    return m_szErrorPrefix;
}

int Lex::GetColumn()
{
	if(m_pStr<m_szBuffer) return 0;
    return (m_pStr - m_szBuffer) - strlen(m_szToken)+1;
}
